{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用Super函数\n",
    "\n",
    "假设有如下情况的继承函数:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Aaaah ...\n",
      "No, thanks!\n",
      "Squawk!\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'SongBird' object has no attribute 'hungry'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-14-ccb3d430edc6>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     25\u001b[0m \u001b[0msb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msing\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     26\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 27\u001b[0;31m \u001b[0msb\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0meat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-14-ccb3d430edc6>\u001b[0m in \u001b[0;36meat\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0meat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m         \u001b[0;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhungry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      7\u001b[0m             \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"Aaaah ...\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mhungry\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'SongBird' object has no attribute 'hungry'"
     ]
    }
   ],
   "source": [
    "class Bird(object):\n",
    "    def __init__(self):\n",
    "        self.hungry = True  # 父类中有属性hungry\n",
    "    \n",
    "    def eat(self):\n",
    "        if self.hungry:\n",
    "            print(\"Aaaah ...\")\n",
    "            self.hungry = False\n",
    "        else:\n",
    "            print(\"No, thanks!\")\n",
    "            \n",
    "class SongBird(Bird):\n",
    "    # 子类重写构建函数会覆盖父类的构造函数\n",
    "    def __init__(self):\n",
    "        self.sound = 'Squawk!'\n",
    "        \n",
    "    def sing(self):\n",
    "        print(self.sound)\n",
    "            \n",
    "b = Bird()\n",
    "b.eat()\n",
    "b.eat()\n",
    "\n",
    "sb = SongBird()\n",
    "sb.sing()\n",
    "\n",
    "sb.eat() # 子类实例调用父类中的接口函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在运行的时候，会出现错误：`SongBird`没有属性`hungry`。因为在`SongBird`中重写了构造函数，但新的构造函数没有包含任何初始化属性`hungry`的代码。要消除这种错误，`SongBird`的构造函数必须调用其超类`（ Bird）`的构造函数，以确保基本的初始化得以执行。为此，有两种方法：**调用未关联的超类构造函数**，以及使用函数**super**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调用未关联的超类构造函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Aaaah ...\n",
      "No, thanks!\n",
      "Squawk!\n",
      "Aaaah ...\n"
     ]
    }
   ],
   "source": [
    "class Bird(object):\n",
    "    def __init__(self):\n",
    "        self.hungry = True\n",
    "    \n",
    "    def eat(self):\n",
    "        if self.hungry:\n",
    "            print(\"Aaaah ...\")\n",
    "            self.hungry = False\n",
    "        else:\n",
    "            print(\"No, thanks!\")\n",
    "            \n",
    "class SongBird(Bird):\n",
    "    # 子类重写构建函数会覆盖父类的构造函数\n",
    "    def __init__(self):\n",
    "        Bird.__init__(self) # 未关联方式调用父类初始化函数\n",
    "        self.sound = 'Squawk!'\n",
    "        \n",
    "    def sing(self):\n",
    "        print(self.sound)\n",
    "            \n",
    "b = Bird()\n",
    "b.eat()\n",
    "b.eat()\n",
    "\n",
    "sb = SongBird()\n",
    "sb.sing()\n",
    "\n",
    "sb.eat()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对实例调用方法时，方法的参数self将自动关联到实例（称为**关联的方法**），这样的示例你见过多个。然而，如果你通过类调用方法（如`Bird.__init__`），就没有实例与其相关联。在这种情况下，你可随便设置参数`self`。这样的方法称为**未关联的**。通过将这个未关联方法的`self`参数设置为当前实例，将使用超类的构造函数来初始化.`SongBird`对象。这意味着将设置其属性`hungry`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用super函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Aaaah ...\n",
      "No, thanks!\n",
      "Squawk!\n",
      "Aaaah ...\n"
     ]
    }
   ],
   "source": [
    "class Bird(object):\n",
    "    def __init__(self):\n",
    "        self.hungry = True # 父类中有hungry属性\n",
    "        \n",
    "    def eat(self):\n",
    "        if self.hungry:\n",
    "            print(\"Aaaah ...\")\n",
    "            self.hungry = False\n",
    "        else:\n",
    "            print(\"No, thanks!\")\n",
    "            \n",
    "class SongBird(Bird):\n",
    "    # 子类重写构建函数会覆盖父类的构造函数\n",
    "    def __init__(self):\n",
    "        super().__init__() # 调用super函数\n",
    "        self.sound = 'Squawk!'\n",
    "        \n",
    "    def sing(self):\n",
    "        print(self.sound)\n",
    "            \n",
    "b = Bird()\n",
    "b.eat()\n",
    "b.eat()\n",
    "\n",
    "sb = SongBird()\n",
    "sb.sing()\n",
    "\n",
    "sb.eat()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数super很聪明，因此即便有多个超类，也只需调用函数super一次（条件是所有超类的构造函数也使用函数super）。\n",
    "\n",
    "**函数super返回的到底是什么呢？**通常，你无需关心这个问题，只管假定它返回你所需的超类即可。实际上，它返回的是一个super对象，这个对象将负责为你执行方法解析。当你访问它的属性时，它将在所有的超类（以及超类的超类等等）中查找，直到找到指定的属性或引发AttributeError异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
